﻿#include "CDeviceSettingsWidget.h"

#include <iostream>

#include "core/CDeviceManager.h"
#include "zlbase/zlbase.h"

CDeviceSettingsWidget::CDeviceSettingsWidget(QWidget *parent) :
    QWidget(parent)
{
    ui.setupUi(this);
    setWindowTitle(tr("Device Settings"));

    // default
    init_view();

    device_config_ = CDeviceManager::Instance().GetDeviceConfig();
    ui.panel_devices->setDeviceConfig(device_config_);

    // connect
    connect(ui.panel_devices, &CPanelDeviceList::deviceChanged,
            this, CDeviceSettingsWidget::eventDeviceChanged);
    connect(ui.combo_board_type, SIGNAL(currentIndexChanged(int)),
            ui.combo_protocol_type, SLOT(setCurrentIndex(int)));
}

CDeviceSettingsWidget::~CDeviceSettingsWidget()
{
}

void CDeviceSettingsWidget::Reset()
{
    // reset device list
    device_config_ = CDeviceManager::Instance().GetDeviceConfig();
    ui.panel_devices->setDeviceConfig(device_config_);

    // reset view
    ui.combo_device_type->setCurrentIndex(0);
    reset_view();
}

void CDeviceSettingsWidget::init_view()
{
    // set default items to combo number/com
    for (int i = 1; i < 256; ++i)
    {
        ui.combo_board_number->addItem(QString::number(i));
    }
#ifdef WIN32
    for (int i = 1; i < 40; ++i)
    {
        ui.combo_datalink_com->addItem(QString("COM%1").arg(i));
    }
#else
    for (int i = 1; i < 16; ++i)
    {
        ui.combo_datalink_com->addItem(QString("/dev/ttymxc%1").arg(i));
    }
#endif

    // default combo protocol type
    ui.combo_board_type->addItem(tr("Door Control Board"), zl::zlbase::EDeviceType_DCB);
    ui.combo_board_type->addItem(tr("Monitor Control Board"), zl::zlbase::EDeviceType_MCB);
    ui.combo_board_type->addItem(tr("Temperature Control Board"), zl::zlbase::EDeviceType_TCB);
    ui.combo_protocol_type->addItem(tr("Door Control Board"), zl::zlbase::EProtocolType_DCB);
    ui.combo_protocol_type->addItem(tr("Monitor Control Board"), zl::zlbase::EProtocolType_MCB);
    ui.combo_protocol_type->addItem(tr("Temperature Control Board"), zl::zlbase::EProtocolType_TCB);
    ui.combo_datalink_type->addItem(tr("Ethernet UDP"), zl::zlbase::EDatalinkType_EthernetUdp);
    // ui.combo_datalink_type->addItem(tr("Ethernet TCP"), zl::zlbase::EDatalinkType_EthernetTcp);
    ui.combo_datalink_type->addItem(tr("Serial Port"), zl::zlbase::EDatalinkType_Serialport);

    ui.combo_datalink_parity->addItem(tr("None Parity"), 0);  // none
    ui.combo_datalink_parity->addItem(tr("Odd Parity"), 1);   // odd
    ui.combo_datalink_parity->addItem(tr("Even Parity"), 2);  // even

    ui.combo_datalink_stopbits->addItem("1", 0);    // 1
    ui.combo_datalink_stopbits->addItem("1.5", 1);  // 1.5
    ui.combo_datalink_stopbits->addItem("2", 2);    // 2

    ui.wnd_settings_ethernet->hide();
    ui.wnd_settings_serial->hide();
}

void CDeviceSettingsWidget::reset_view()
{
    ui.wnd_content->setCurrentIndex(0);
    ui.edt_board_name->clear();
    ui.edt_board_id->clear();
    ui.combo_board_type->setCurrentIndex(0);
    ui.combo_board_number->setCurrentIndex(0);
    ui.combo_protocol_type->setCurrentIndex(0);
    ui.combo_protocol_name->setCurrentIndex(0);
    ui.edt_protocol_version->clear();
    ui.edt_protocol_uuid->clear();
    ui.combo_datalink_type->setCurrentIndex(0);
    ui.ck_datalink_isshared->setChecked(false);
    ui.edt_datalink_localaddr->clear();
    ui.edt_datalink_localport->setText("30000");
    ui.edt_datalink_remoteaddr->setText("192.168.1.10");
    ui.edt_datalink_remoteport->setText("30000");
    ui.combo_datalink_com->setCurrentIndex(0);
    ui.combo_datalink_baud->setCurrentIndex(3);
    ui.combo_datalink_parity->setCurrentIndex(0);
    ui.combo_datalink_stopbits->setCurrentIndex(0);
    ui.combo_datalink_charactersize->setCurrentIndex(2);
    ui.wnd_settings_ethernet->hide();
    ui.wnd_settings_serial->hide();
}

bool CDeviceSettingsWidget::check_user_input()
{
    if (ui.combo_device_type->currentIndex() == 0)
    {
        return false;
    }

    if (ui.combo_board_type->currentIndex() == 0)
    {
        return false;
    }

    if (ui.combo_board_number->currentIndex() == 0)
    {
        return false;
    }

    if (ui.combo_protocol_type->currentIndex() == 0)
    {
        return false;
    }

    if (ui.combo_protocol_name->currentIndex() == 0)
    {
        return false;
    }

    if (ui.combo_datalink_type->currentIndex() == 0)
    {
        return false;
    }

    return true;
}

QString CDeviceSettingsWidget::generater_device_id()
{
    int max_id = 0;
    for (const auto &d : device_config_.zlbase_info.devices)
    {
        auto tmp = QString(d.id.c_str()).toInt();
        max_id = tmp > max_id ? tmp : max_id;
    }
    for (const auto &d : device_config_.peripherals_info.devices)
    {
        // todo
    }

    max_id += max_id > 1000 ? 0 : 1000;
    std::cout << "new device id: " << max_id << std::endl;
    return QString::number(max_id + 1);
}

void CDeviceSettingsWidget::set_zlbase_device(const ZLBaseDevice &device)
{
    // device info
    ui.combo_device_type->setCurrentIndex(1);
    on_combo_device_type_currentIndexChanged(1);

    // board info
    ui.edt_board_name->setText(device.name.c_str());
    ui.edt_board_id->setText(device.id.c_str());
    auto index_board_type = ui.combo_board_type->findData(device.type);
    ui.combo_board_type->setCurrentIndex(index_board_type);
    ui.combo_board_number->setCurrentIndex(device.number);

    // protocol info
    auto index3 = ui.combo_protocol_type->findData(device.protocol.type);
    on_combo_protocol_type_currentIndexChanged(index3);

    ui.combo_protocol_type->setCurrentIndex(index3);
    auto index4 = ui.combo_protocol_name->findData(QString(device.protocol.uuid.c_str()));
    ui.combo_protocol_name->setCurrentIndex(index4);
    ui.edt_protocol_version->setText(device.protocol.version.c_str());
    ui.edt_protocol_uuid->setText(device.protocol.uuid.c_str());

    // datalink info
    auto index5 = ui.combo_datalink_type->findData(device.datalink.type);
    on_combo_datalink_type_currentIndexChanged(index5);

    ui.combo_datalink_type->setCurrentIndex(index5);
    ui.ck_datalink_isshared->setChecked(device.datalink.is_shared);
    ui.ck_datalink_enable_debug->setChecked(device.enable_debug);

    ui.edt_datalink_localaddr->setText(device.datalink.localaddr);
    ui.edt_datalink_localport->setText(QString::number(device.datalink.localport));
    ui.edt_datalink_remoteaddr->setText(device.datalink.remoteaddr);
    ui.edt_datalink_remoteport->setText(QString::number(device.datalink.remoteport));

    auto index_com = ui.combo_datalink_com->findText(QString(device.datalink.com));
    ui.combo_datalink_com->setCurrentIndex(index_com);
    auto index_baud = ui.combo_datalink_baud->findText(QString::number(device.datalink.baud_rate));
    ui.combo_datalink_baud->setCurrentIndex(index_baud);
    auto index_parity = ui.combo_datalink_parity->findData(device.datalink.parity);
    ui.combo_datalink_parity->setCurrentIndex(index_parity);
    auto index_stopbits = ui.combo_datalink_stopbits->findData(device.datalink.stop_bits);
    ui.combo_datalink_stopbits->setCurrentIndex(index_stopbits);
    auto index_charactersize = ui.combo_datalink_charactersize->findText(QString::number(device.datalink.character_size));
    ui.combo_datalink_charactersize->setCurrentIndex(index_charactersize);
}

void CDeviceSettingsWidget::get_zlbase_device(ZLBaseDevice &device)
{
    // board info
    device.name = ui.edt_board_name->text().toStdString();
    device.id = ui.edt_board_id->text().toStdString();
    device.type = ui.combo_board_type->currentData().toInt();
    device.number = ui.combo_board_number->currentText().toInt();

    // protocol info
    device.protocol.type = ui.combo_protocol_type->currentData().toInt();
    device.protocol.name = ui.combo_protocol_name->currentText().toStdString();
    device.protocol.uuid = ui.edt_protocol_uuid->text().toStdString();
    device.protocol.version = ui.edt_protocol_version->text().toStdString();

    // datalink info
    device.datalink.type = ui.combo_datalink_type->currentData().toInt();
    device.datalink.is_shared = ui.ck_datalink_isshared->isChecked();
    device.enable_debug = ui.ck_datalink_enable_debug->isChecked();
    strncpy(device.datalink.localaddr,
            ui.edt_datalink_localaddr->text().toStdString().c_str(),
            sizeof(device.datalink.localaddr));
    device.datalink.localport = ui.edt_datalink_localport->text().toInt();
    strncpy(device.datalink.remoteaddr,
            ui.edt_datalink_remoteaddr->text().toStdString().c_str(),
            sizeof(device.datalink.remoteaddr));
    device.datalink.remoteport = ui.edt_datalink_remoteport->text().toInt();
    strncpy(device.datalink.com,
            ui.combo_datalink_com->currentText().toStdString().c_str(),
            sizeof(device.datalink.com));
    device.datalink.baud_rate = ui.combo_datalink_baud->currentText().toInt();
    device.datalink.parity = ui.combo_datalink_parity->currentData().toInt();
    device.datalink.stop_bits = ui.combo_datalink_stopbits->currentData().toInt();
    device.datalink.character_size = ui.combo_datalink_charactersize->currentText().toInt();
}

void CDeviceSettingsWidget::set_peripherals_device(const ZLPeripheralsDevice &device)
{
    // todo
}

void CDeviceSettingsWidget::get_peripherals_device(ZLPeripheralsDevice &device)
{
    // todo
}

void CDeviceSettingsWidget::on_btn_close_clicked()
{
    close();
}

void CDeviceSettingsWidget::on_btn_add_clicked()
{
    // check user input
    if (!check_user_input())
    {
        return;
    }

    // get device info
    ZLBaseDevice device;
    get_zlbase_device(device);

    // generater new device id
    device.id = generater_device_id().toStdString();

    // save to device config
    device_config_.zlbase_info.devices.push_back(device);

    // update device list
    ui.panel_devices->setDeviceConfig(device_config_);
}

void CDeviceSettingsWidget::on_btn_modify_clicked()
{
    // check user input
    if (!check_user_input())
    {
        return;
    }

    // get device info
    ZLBaseDevice device;
    get_zlbase_device(device);

    // modify device config
    auto iter = device_config_.zlbase_info.devices.begin();
    auto cend = device_config_.zlbase_info.devices.cend();
    while (iter != cend)
    {
        if (iter->id == device.id)
        {
            *iter = device;
            break;
        }
        ++iter;
    }

    // update device list
    ui.panel_devices->setDeviceConfig(device_config_);
}

void CDeviceSettingsWidget::on_btn_delete_clicked()
{
    std::string id = ui.edt_board_id->text().toStdString();
    if (id.empty())
    {
        return;
    }

    // delete device
    auto iter = device_config_.zlbase_info.devices.begin();
    while (iter != device_config_.zlbase_info.devices.cend())
    {
        if (iter->id == id)
        {
            iter = device_config_.zlbase_info.devices.erase(iter);
            continue;
        }

        ++iter;
    }

    // update device list
    ui.panel_devices->setDeviceConfig(device_config_);
    eventDeviceChanged("");
}

void CDeviceSettingsWidget::on_btn_save_clicked()
{
    // save to config xml file
    CDeviceManager::Instance().SetDeviceConfig(device_config_);
    CDeviceManager::Instance().SaveDeviceConfiguration();

    emit deviceConfigChanged();

    close();
}

void CDeviceSettingsWidget::on_combo_device_type_currentIndexChanged(int index)
{
    reset_view();
    ui.wnd_content->setCurrentIndex(index);
}

void CDeviceSettingsWidget::on_combo_protocol_type_currentIndexChanged(int index)
{
    // clear origin
    ui.combo_protocol_name->clear();
    ui.combo_protocol_name->addItem(tr("Please select"));

    // get protocol list
    auto protocol_type = ui.combo_protocol_type->itemData(index).toInt();
    std::vector<ZLBasePlugin> plugins;
    CDeviceManager::Instance().GetPlugins(protocol_type, plugins);
    for (const auto &plugin : plugins)
    {
        ui.combo_protocol_name->addItem(plugin.name.c_str(), plugin.uuid.c_str());
    }
    ui.combo_protocol_name->setCurrentIndex(0);

    // 设置默认设备名称
    ui.edt_board_name->setText(ui.combo_board_type->currentText());
    if (ui.combo_board_type->currentIndex() == 0)
    {
        ui.edt_board_name->clear();
    }
}

void CDeviceSettingsWidget::on_combo_protocol_name_currentIndexChanged(int index)
{
    // clear edt
    ui.edt_protocol_version->clear();
    ui.edt_protocol_uuid->clear();

    auto uuid = ui.combo_protocol_name->itemData(index).toString();
    if (uuid.isEmpty())
    {
        return;
    }

    ZLBasePlugin plugin;
    auto ret = CDeviceManager::Instance().GetPluginInfo(uuid.toStdString(), plugin);
    if (!ret)
    {
        return;
    }

    ui.edt_protocol_version->setText(plugin.version.c_str());
    ui.edt_protocol_uuid->setText(plugin.uuid.c_str());
}

void CDeviceSettingsWidget::on_combo_datalink_type_currentIndexChanged(int index)
{
    ui.wnd_settings_ethernet->hide();
    ui.wnd_settings_serial->hide();

    if (index == 1 || index == 2)
    {
        ui.wnd_settings_ethernet->show();
    }
    else if (index == 3)
    {
        ui.wnd_settings_serial->show();
    }
}

void CDeviceSettingsWidget::eventDeviceChanged(QString id)
{
    reset_view();
    for (const auto &device : device_config_.zlbase_info.devices)
    {
        if (device.id == id.toStdString())
        {
            set_zlbase_device(device);
            return;
        }
    }
}
